import pako from 'pako';
import { showloading, hideloading } from '../global/loading';
import { luckysheetrefreshgrid, jfrefreshgrid_rhcw } from '../global/refresh';
import editor from '../global/editor';
import { sheetHTML, luckyColor } from './constant';
import sheetmanage from './sheetmanage';
import menuButton from './menuButton';
import { createFilterOptions } from './filter';
import luckysheetFreezen from './freezen';
import luckysheetPostil from './postil';
import imageCtrl from './imageCtrl';
import dataVerificationCtrl from './dataVerificationCtrl';
import hyperlinkCtrl from './hyperlinkCtrl';
import { getObjType, replaceHtml, getByteLen } from '../utils/util';
import { getSheetIndex } from '../methods/get';
import Store from '../store';
import { collaborativeEditBox } from './select';
import locale from '../locale/locale';
import dayjs from "dayjs";
import json from '../global/json';
import luckysheetConfigsetting from './luckysheetConfigsetting';
import { customImageUpdate } from './imageUpdateCtrl';
import method from '../global/method';

const server = {
    gridKey: null,
    loadUrl: null,
    updateUrl: null,
    updateImageUrl: null,
    title: null,
    loadSheetUrl: null,
    retryTimer: null,
    allowUpdate: false, // 共享编辑模式
    historyParam: function (data, sheetIndex, range) {
    	let _this = this;

	    let r1 = range.row[0], r2 = range.row[1];
	    let c1 = range.column[0], c2 = range.column[1];

	    if (r1 == r2 && c1 == c2) { // 单个单元格更新
	        let v = data[r1][c1];
	        _this.saveParam("v", sheetIndex, v, { "r": r1, "c": c1 });
	    } else { // 范围单元格更新
	        let rowlen = r2 - r1 + 1;
	        let collen = c2 - c1 + 1;

	        let timeR = Math.floor(1000 / collen);
	        let n = Math.ceil(rowlen / timeR); // 分批次更新，一次最多1000个单元格

	        for (let i = 0; i < n; i++) {
	            let str = r1 + timeR * i;

                let edr;
	            if (i == n - 1) {
	                edr = r2;
	            } else {
	                edr = r1 + timeR * (i + 1) - 1;
	            }

	            let v = [];

	            for (let r = str; r <= edr; r++) {
	                let v_row = [];

	                for (let c = c1; c <= c2; c++) {
                        if (data[r] == null) {
                            v_row.push(null);
                        } else {
                            v_row.push(data[r][c]);
                        }
	                }

	                v.push(v_row);
	            }

	            _this.saveParam("rv", sheetIndex, v, { "range": { "row": [str, edr], "column": [c1, c2] } });

	            if (i == n - 1) {
	                _this.saveParam("rv_end", sheetIndex, null);
	            }
	        }
	    }
    },
    saveParam: function (type, index, value, params) {
    	let _this = this;

	    if (!_this.allowUpdate) {
	        return;
	    }

	    if (value == undefined) {
	        value = null;
	    }

	    let d = {};
	    d.t = type;
	    d.i = index;
	    d.v = value;

        // 切换sheet页不发后台，TODO：改为发后台+后台不广播
        if (type === 'shs') {
            return;
        }

	    if (type == "rv") { // 单元格批量更新
	        d.range = params.range;
	    } else if (type == "v" || type == "fu" || type == "fm") {
	        d.r = params.r;
	        d.c = params.c;
	    } else if (type == "fc") {
	        d.op = params.op;
	        d.pos = params.pos;
	    } else if (type == "drc" || type == "arc" || type == "h" || type == "wh") {
	        d.rc = params.rc;
	    } else if (type == "c") {
	        d.cid = params.cid;
	        d.op = params.op;
	    } else if (type == "f") {
	        d.op = params.op;
	        d.pos = params.pos;
	    } else if (type == "s") {

	    } else if (type == "sh") {
	        d.op = params.op;
	        if (params.cur != null) {
	            d.cur = params.cur;
	        }
	    } else if (type == "cg") {
	        d.k = params.k;
	    } else if (type == "all") {
	        d.k = params.k;
	        // d.s = params.s;
	    }

	    // TODO 配置自定义方式同步图片
        const customImageUpdateMethodConfig = luckysheetConfigsetting.imageUpdateMethodConfig;
        if (JSON.stringify(customImageUpdateMethodConfig) !== "{}") {
            if (d.k != "images") {
                let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), { to: "string" });

                if (_this.websocket != null) {
                    _this.websocket.send(msg);
                }
            } else {
                customImageUpdate(customImageUpdateMethodConfig.method, customImageUpdateMethodConfig.url, d)
                    .then((data) => {
                        console.log(data);
                    })
                    .catch((err) => {
                        console.log(err);
                    });
            }
        } else {
            let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), { to: "string" });
            if (_this.websocket != null) {
                _this.websocket.send(msg);
            }
        }
    },
    websocket: null,
    wxErrorCount: 0,
    openWebSocket: function () {
        let _this = this;

        if ('WebSocket' in window) {
            let wxUrl = _this.updateUrl + "?t=111&g=" + encodeURIComponent(_this.gridKey);
            if (_this.updateUrl.indexOf('?') > -1) {
                wxUrl = _this.updateUrl + "&t=111&g=" + encodeURIComponent(_this.gridKey);
            }

	        _this.websocket = new WebSocket(wxUrl);

	        // 连接建立时触发
	        _this.websocket.onopen = function () {
	        	console.info(locale().websocket.success);
	        	hideloading();
                _this.wxErrorCount = 0;

	            // 防止websocket长时间不发送消息导致断连
                _this.retryTimer = setInterval(function () {
	                _this.websocket.send("rub");
	            }, 60000);
	        };

	        // 客户端接收服务端数据时触发
	        _this.websocket.onmessage = function (result) {
                Store.result = result;
                let data = new Function("return " + result.data)();
                method.createHookFunction('cooperativeMessage', data);
                console.info(data);
                let type = data.type;
                let { message, id } = data;
                // 用户退出时，关闭协同编辑时其提示框
                if (message === '用户退出') {
                    $("#luckysheet-multipleRange-show-" + id).hide();
                    Store.cooperativeEdit.changeCollaborationSize = Store.cooperativeEdit.changeCollaborationSize.filter(value => {
                        return value.id != id;
                    });
                    Store.cooperativeEdit.checkoutData = Store.cooperativeEdit.checkoutData.filter(value => {
                        return value.id != id;
                    });
                }
	            if (type == 1) { // send 成功或失败
                    const oldIndex = data.data.v.index;
                    const sheetToUpdate = Store.luckysheetfile.filter((sheet) => sheet.index === oldIndex)[0];
                    if (sheetToUpdate !== null) {
                        setTimeout(() => {
                            const index = data.data.i;
                            sheetToUpdate.index = index;
                            Store.currentSheetIndex = index;

                            $(`#luckysheet-sheets-item${oldIndex}`).attr('data-index', index);
                            $(`#luckysheet-sheets-item${oldIndex}`).prop('id', `luckysheet-sheets-item${index}`);
                            $(`#luckysheet-datavisual-selection-set-${oldIndex}`).prop('id', `luckysheet-datavisual-selection-set-${index}`);
                        }, 1);
                    }
	            } else if (type == 2) { // 更新数据
	                let item = JSON.parse(data.data);
                    _this.wsUpdateMsg(item);
                    let chang_data = JSON.parse(data.data);
                    if (chang_data.k == 'columnlen') {
                        collaborativeEditBox(chang_data.v, null);
                    } else if (chang_data.k == 'rowlen') {
                        collaborativeEditBox(null, chang_data.v);
                    }
	            } else if (type == 3) { // 多人操作不同选区("t": "mv")（用不同颜色显示其他人所操作的选区）
	                let id = data.id;
	                let username = data.username;
	                let item = JSON.parse(data.data);
	                let type = item.t,
	                    index = item.i,
	                    value = item.v;
                    if (Store.cooperativeEdit.changeCollaborationSize.length === 0) {
                        Store.cooperativeEdit.changeCollaborationSize.push({ id: id, v: item.v[0], i: index });
                    }
                    let flag = Store.cooperativeEdit.changeCollaborationSize.some(value1 => {
                        return value1.id == id;
                    });
                    if (flag) {
                        Store.cooperativeEdit.changeCollaborationSize.forEach(val => {
                            if (val.id == id) {
                                val.v = item.v[0] || item.range[0];
                                val.i = index;
                            }
                        });
                    } else {
                        Store.cooperativeEdit.changeCollaborationSize.push({ id: id, v: item.v[0], i: index });
                    }
	                if (getObjType(value) != "array" && getObjType(value) !== "object") {
	                    value = JSON.parse(value);
                    }
                    let r = 0;
                    let c = 0;
                    if (index == Store.currentSheetIndex) { // 发送消息者在当前页面
                        if (getObjType(value) === "object" && value.op === 'enterEdit') {
                            r = value.range[value.range.length - 1].row[0];
                            c = value.range[value.range.length - 1].column[0];
                            _this.multipleRangeShow(id, username, r, c, value.op);
                        } else {
                            r = value[value.length - 1].row[0];
                            c = value[value.length - 1].column[0];

                            _this.multipleRangeShow(id, username, r, c);
                        }
                    } else {
                        if (getObjType(value) === "object" && value.op === 'enterEdit') {
                            r = value.range[value.range.length - 1].row[0];
                            c = value.range[value.range.length - 1].column[0];
                        } else {
                            r = value[value.length - 1].row[0];
                            c = value[value.length - 1].column[0];
                        }
                    }

                    if (Store.cooperativeEdit.checkoutData.length === 0) {
                        if (value.op) {
                            Store.cooperativeEdit.checkoutData.push({ id, username, r, c, op: value.op, index });
                        } else {
                            Store.cooperativeEdit.checkoutData.push({ id, username, r, c, index });
                        }
                    }
                    let checkoutFlag = Store.cooperativeEdit.checkoutData.some(item => {
                        return item.id == id;
                    });
                    if (checkoutFlag) {
                        Store.cooperativeEdit.checkoutData.forEach(item => {
                            if (item.id == id) {
                                item.username = username;
                                item.r = r;
                                item.c = c;
                                item.index = index;
                                if (value.op === 'enterEdit') {
                                    item.op = value.op;
                                }
                            }
                        });
                    } else {
                        if (value.op === 'enterEdit') {
                            Store.cooperativeEdit.checkoutData.push({ id, username, r, c, op: value.op, index });
                        } else {
                            Store.cooperativeEdit.checkoutData.push({ id, username, r, c, index });
                        }
                    }

                    // 其他客户端切换页面时
                    Store.cooperativeEdit.checkoutData.forEach(item => {
                        if (item.index != Store.currentSheetIndex) {
                            $("#luckysheet-multipleRange-show-" + item.id).hide();
                            item.op = '';
                        }
                    });

                    if ($("#luckysheet-multipleRange-show-" + id)[0]) {
                        let change_bottom = $("#luckysheet-multipleRange-show-" + id)[0].offsetHeight - 1;
                        $("#luckysheet-multipleRange-show-" + id + ">.username").css({ "bottom": change_bottom + 'px' });
                    }
	            } else if (type == 4) { // 批量指令更新
                    // let items = JSON.parse(data.data);

                    // After editing by multiple people, data.data may appear as an empty string
                    let items = data.data === "" ?  data.data : JSON.parse(data.data);

	                for (let i = 0; i < items.length; i++) {
	                    _this.wsUpdateMsg(items[i]);
	                }
	            } else if (type == 5) {
                    showloading(data.data);
                } else if (type == 6) {
                    hideloading();
                }
	        };

	        // 通信发生错误时触发
	        _this.websocket.onerror = function () {
	            _this.wxErrorCount++;

	            if (_this.wxErrorCount > 3) {
	                showloading(locale().websocket.refresh);
	            } else {
	                showloading(locale().websocket.wait);
	                _this.openWebSocket();
	            }
	        };

	        // 连接关闭时触发
	        _this.websocket.onclose = function (e) {
                console.info(locale().websocket.close);
                if (e.code === 1000) {
                    clearInterval(_this.retryTimer);
                    _this.retryTimer = null;
                } else {
                    alert(locale().websocket.contact);
                }
	        };
	    } else {
	        alert(locale().websocket.support);
	    }
    },
    wsUpdateMsg: function (item) {
	    let type = item.t,
	        index = item.i,
	        value = item.v;

	    let file = Store.luckysheetfile[getSheetIndex(index)];

	    if (["v", "rv", "cg", "all", "fc", "drc", "arc", "f", "fsc", "fsr", "sh", "c"].includes(type) && file == null) {
	        return;
	    }

	    if (type == "v") { // 单个单元格数据更新
	        if (file.data == null || file.data.length == 0) {
	            return;
	        }

	        let r = item.r, c = item.c;
	        file.data[r][c] = value;

	        if (index == Store.currentSheetIndex) { // 更新数据为当前表格数据
                Store.flowdata = file.data;
                editor.webWorkerFlowDataCache(Store.flowdata);// worker存数据

	            // 如果更新的单元格有批注
	            if (value != null && value.ps != null) {
	                luckysheetPostil.buildPs(r, c, value.ps);
	            } else {
	                luckysheetPostil.buildPs(r, c, null);
	            }

	            setTimeout(function () {
	                luckysheetrefreshgrid();
	            }, 1);
	        }
	    } else if (type == "rv") { // 范围单元格数据更新
            if (Object.keys(item.range).length > 0) {
                Store.cooperativeEdit.merge_range = item.range;
                Store.cooperativeEdit.merge_range.v = item.v;
                collaborativeEditBox();
            }
	        if (file.data == null || file.data.length == 0) {
	            return;
	        }

	        let r1 = item.range.row[0], r2 = item.range.row[1];
	        let c1 = item.range.column[0], c2 = item.range.column[1];

	        for (let r = r1; r <= r2; r++) {
	            for (let c = c1; c <= c2; c++) {
	                file.data[r][c] = value[r - r1][c - c1];
	            }
	        }

	        if (index == Store.currentSheetIndex) { // 更新数据为当前表格数据
                Store.flowdata = file.data;
                editor.webWorkerFlowDataCache(Store.flowdata);// worker存数据

	            // 如果更新的单元格有批注
	            for (let r = r1; r <= r2; r++) {
	                for (let c = c1; c <= c2; c++) {
	                    if (value[r - r1][c - c1] != null && value[r - r1][c - c1].ps != null) {
	                        luckysheetPostil.buildPs(r, c, value[r - r1][c - c1].ps);
	                    } else {
	                        luckysheetPostil.buildPs(r, c, null);
	                    }
	                }
	            }

	            setTimeout(function () {
	                luckysheetrefreshgrid();
	            }, 1);
            }
	    } else if (type == "cg") { // config更新（rowhidden，rowlen，columnlen，merge，borderInfo）
	        let k = item.k;

	        if (k == "borderInfo") {
                file.config.borderInfo = value;
	        } else {
	            if (!(k in file.config)) {
	                file.config[k] = {};
	            }

	            // for(let key in value){
	            //     file["config"][k][key] = value[key];
                // }

                // ⚠️ 上面的处理方式会导致部分配置项被遗漏，以致协同编辑的时候多视图出现不一致的情况，调整处理的策略为直接替换配置项：
                // 可能的配置项为：
                // columnlen: {0: 65, 1: 186, 2: 52}
                // customHeight: {0: 1, 5: 1, 6: 1}
                // customWidth: {0: 1, 1: 1, 2: 1}
                // merge: {2_1: {…}, 4_2: {…}, 6_2: {…}}
                // rowlen: {0: 19, 5: 93, 6: 117}
                if (value && (typeof value == "object")) {
                    file.config[k] = value;
                }
	        }

	        if (index == Store.currentSheetIndex) { // 更新数据为当前表格数据
	            Store.config = file.config;

	            if (k == "rowlen" || k == "columnlen" || k == "rowhidden") {
	                jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
	            }

	            setTimeout(function () {
	                luckysheetrefreshgrid();
	            }, 1);
	        }
	    } else if (type == "all") { // 通用保存更新
	        let k = item.k;
	        file[k] = value;

	        if (k == "name") { // 工作表名
	            $("#luckysheet-sheet-container-c #luckysheet-sheets-item" + index).find("span.luckysheet-sheets-item-name").html(value);
	        } else if (k == "color") { // 工作表颜色
	            let currentSheetItem = $("#luckysheet-sheet-container-c #luckysheet-sheets-item" + index);
	            currentSheetItem.find(".luckysheet-sheets-item-color").remove();

	            if (value != null || value != "") {
	                currentSheetItem.append('<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 2px; left: 0px; background-color: ' + value + ';"></div>');
	            }
	        } else if (k == "pivotTable") { // PivotTable
	            // luckysheet.pivotTable.changePivotTable(index);
	        } else if (k == "frozen") { // freezen row and column
                // tranform frozen
                luckysheetFreezen.frozenTofreezen();

	            if (index == Store.currentSheetIndex) {
                    const _locale = locale();
                    const locale_freezen = _locale.freezen;
	                if (file.freezen.horizontal == null) {
	                    $("#luckysheet-freezen-btn-horizontal").html('<i class="fa fa-list-alt"></i> ' + locale_freezen.freezenRow);
	                    luckysheetFreezen.freezenhorizontaldata = null;
	                    $("#luckysheet-freezebar-horizontal").hide();
	                } else {
	                    luckysheetFreezen.createFreezenHorizontal(file.freezen.horizontal.freezenhorizontaldata, file.freezen.horizontal.top);
	                }

	                if (file.freezen.vertical == null) {
	                    $("#luckysheet-freezen-btn-vertical").html('<i class="fa fa-indent"></i> ' + locale_freezen.freezenColumn);
	                    luckysheetFreezen.freezenverticaldata = null;
	                    $("#luckysheet-freezebar-vertical").hide();
	                } else {
	                    luckysheetFreezen.createFreezenVertical(file.freezen.vertical.freezenverticaldata, file.freezen.vertical.left);
	                }

	                luckysheetFreezen.createAssistCanvas();
	            }
	        } else if (k == "filter_select") { // 筛选范围
	            if (index == Store.currentSheetIndex) {
	                createFilterOptions(value);
	            }
	        } else if (k == "filter") { // 筛选保存
	            if (index == Store.currentSheetIndex) {
	                createFilterOptions(file.filter_select, value);
	            }
	        } else if (k == "luckysheet_conditionformat_save") { // 条件格式
	            if (index == Store.currentSheetIndex) {
	                setTimeout(function () {
	                    luckysheetrefreshgrid();
	                }, 1);
	            }
	        } else if (k == "luckysheet_alternateformat_save") { // 交替颜色
	            if (index == Store.currentSheetIndex) {
	                setTimeout(function () {
	                    luckysheetrefreshgrid();
	                }, 1);
	            }
	        } else if (k == "config") { // config
	            if (index == Store.currentSheetIndex) {
	                Store.config = value;
	                jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
	            }
	        } else if (k == "dynamicArray") { // 动态数组
	            if (index == Store.currentSheetIndex) {
	                setTimeout(function () {
	                    luckysheetrefreshgrid();
	                }, 1);
	            }
            } else if (k == "images") { // 图片
                if (index == Store.currentSheetIndex) {
                    imageCtrl.images = value;
                    imageCtrl.allImagesShow();
                    imageCtrl.init();
                }
            } else if (k == "dataVerification") { // 数据验证
                if (index == Store.currentSheetIndex) {
                    dataVerificationCtrl.dataVerification = value;
        			dataVerificationCtrl.init();
                }
            } else if (k == "hyperlink") { // 链接
                if (index == Store.currentSheetIndex) {
                    hyperlinkCtrl.hyperlink = value;
        			hyperlinkCtrl.init();
                }
            }
	    } else if (type == "fc") { // 函数链calc
	        let op = item.op, pos = item.pos;

	        if (getObjType(value) != "object") {
                value = new Function("return " + value)();
	        }

	        let r = value.r, c = value.c;

	        let calcChain = file.calcChain == null ? [] : file.calcChain;

	        if (op == "add") {
	            calcChain.push(value);
	        } else if (op == "del") {
	            for (let a = 0; a < calcChain.length; a++) {
	                if (r == calcChain[a].r && c == calcChain[a].c && index == calcChain[a].index) {
	                    calcChain.splice(a, 1);
	                }
	            }
	        }
	        // else if(op == "update"){
	        //     for(let a = 0; a < calcChain.length; a++){
	        //         if(r == calcChain[a].r && c == calcChain[a].c && index == calcChain[a].index){
	        //             calcChain[a].func = func;
	        //         }
	        //     }
	        // }

	        setTimeout(function () {
	            luckysheetrefreshgrid();
	        }, 1);
	    } else if (type == "drc") { // 删除行列
	        if (file.data == null || file.data.length == 0) {
	            return;
	        }

	        let rc = item.rc,
	        	st_i = value.index,
	        	len = value.len,
	        	mc = value.mc,
	        	borderInfo = value.borderInfo;
	        let data = file.data;

	        if (rc == "r") {
	            file.row -= len;

	            data.splice(st_i, len);

	            // 空白行模板
	            let row = [];
	            for (let c = 0; c < data[0].length; c++) {
	                row.push(null);
	            }

	            // 删除多少行，增加多少行空白行
	            for (let r = 0; r < len; r++) {
	                data.push(row);
	            }
	        } else {
	            file.column -= len;

	            // 空白列模板
	            let addcol = [];
	            for (let r = 0; r < len; r++) {
	                addcol.push(null);
	            }

	            for (let i = 0; i < data.length; i++) {
	                data[i].splice(st_i, len);

	                data[i] = data[i].concat(addcol);
	            }
	        }

	        for (let x in mc) {
	            let r = mc[x].r, c = mc[x].c;
	            data[r][c].mc = mc[x];
	        }

	        file.config.merge = mc;
	        file.config.borderInfo = borderInfo;

	        if (index == Store.currentSheetIndex) {
                Store.flowdata = data;
                editor.webWorkerFlowDataCache(Store.flowdata);// worker存数据

	            Store.config.merge = mc;
	            Store.config.borderInfo = borderInfo;

	            setTimeout(function () {
	                luckysheetrefreshgrid();
	            }, 1);
	        }
	    } else if (type == "arc") { // 增加行列
	        if (file.data == null || file.data.length == 0) {
	            return;
	        }

	        let rc = item.rc,
	        	st_i = value.index,
	        	len = value.len,
                addData = value.data,
                direction = value.direction,
	        	mc = value.mc,
	        	borderInfo = value.borderInfo;
	        let data = $.extend(true, [], file.data);

	        if (rc == "r") {
                file.row += len;

                // 空行模板
                let row = [];
                for (let c = 0; c < data[0].length; c++) {
                    row.push(null);
                }

	            let arr = [];
	            for (let i = 0; i < len; i++) {
                    if (addData[i] == null) {
                        arr.push(JSON.stringify(row));
                    } else {
                        arr.push(JSON.stringify(addData[i]));
                    }
                }

                if (direction == "lefttop") {
                    if (st_i == 0) {
                        new Function("data", "return " + 'data.unshift(' + arr.join(",") + ')')(data);
                    } else {
                        new Function("data", "return " + 'data.splice(' + st_i + ', 0, ' + arr.join(",") + ')')(data);
                    }
                } else {
                    new Function("data", "return " + 'data.splice(' + (st_i + 1) + ', 0, ' + arr.join(",") + ')')(data);
                }
	        } else {
                file.column += len;

	            for (let i = 0; i < data.length; i++) {
                    /* 在每一行的指定位置都插入一列 */
                    for (let j = 0; j < len; j++) {
                        if (direction == "lefttop") {
                            data[i].splice(st_i, 0, addData[j]);
                        } else {
                            data[i].splice(st_i + 1, 0, addData[j]);
                        }
                    }
	            }
	        }

	        for (let x in mc) {
	            let r = mc[x].r, c = mc[x].c;
	            data[r][c].mc = mc[x];
	        }

            file.data = data;
	        file.config.merge = mc;
	        file.config.borderInfo = borderInfo;

	        if (index == Store.currentSheetIndex) {
                Store.flowdata = data;
                editor.webWorkerFlowDataCache(Store.flowdata);// worker存数据

	            Store.config.merge = mc;
	            Store.config.borderInfo = borderInfo;

	            setTimeout(function () {
	                luckysheetrefreshgrid();
	            }, 1);
	        }
	    } else if (type == "f") { // 筛选
	        let op = item.op, pos = item.pos;

	        let filter = file.filter;

	        if (filter == null) {
	            filter = {};
	        }

	        if (op == "upOrAdd") {
	            filter[pos] =  value;
	        } else if (op == "del") {
	            delete filter[pos];
	        }

	        if (index == Store.currentSheetIndex) {
	            createFilterOptions(file.filter_select, filter);
	        }
	    } else if (type == "fsc") { // 清除筛选
	        file.filter = null;
	        file.filter_select = null;

	        if (index == Store.currentSheetIndex) {
	            $('#luckysheet-filter-selected-sheet' + Store.currentSheetIndex + ', #luckysheet-filter-options-sheet' + Store.currentSheetIndex).remove();
	            $("#luckysheet-filter-menu, #luckysheet-filter-submenu").hide();
	        }
	    } else if (type == "fsr") { // 恢复筛选
	        file.filter = value.filter;
	        file.filter_select = value.filter_select;

	        if (index == Store.currentSheetIndex) {
	            createFilterOptions(file.filter_select, file.filter);
	        }
	    } else if (type == "sha") { // 新建sheet
	        Store.luckysheetfile.push(value);

	        let colorset = '';
	        if (value.color != null) {
	            colorset = '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 2px; left: 0px; background-color: ' + value.color + ';"></div>';
	        }

	        $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": value.index, "active": "", "name": value.name, "style": "", "colorset": colorset }));
	        $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + value.index + '" class="luckysheet-datavisual-selection-set"></div>');

            // *添加sheet之后,要判断是否需要显示sheet滚动按钮
            sheetmanage.locationSheet();
	    } else if (type == "shc") { // 复制sheet
	        let copyindex = value.copyindex, name = value.name;

	        let copyarrindex = getSheetIndex(copyindex);
	        let copyjson = $.extend(true, {}, Store.luckysheetfile[copyarrindex]);

	        copyjson.index = index;
	        copyjson.name = name;

	        Store.luckysheetfile.splice(copyarrindex + 1, 0, copyjson);

	        let copyobject = $("#luckysheet-sheets-item" + copyindex);
	        $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": copyjson.index, "active": "", "name": copyjson.name, "style": "", "colorset": "" }));
	        $("#luckysheet-sheets-item" + copyjson.index).insertAfter(copyobject);
	        $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + copyjson.index + '" class="luckysheet-datavisual-selection-set"></div>');
	    } else if (type == "shd") { // 删除sheet
	        for (let i = 0; i < Store.luckysheetfile.length; i++) {
	            if (Store.luckysheetfile[i].index == value.deleIndex) {
                    // 如果删除的是当前sheet，则切换到前一个sheet页
                    if (Store.currentSheetIndex === value.deleIndex) {
                        const index = value.deleIndex;

                        Store.luckysheetfile[sheetmanage.getSheetIndex(index)].hide = 1;

                        let luckysheetcurrentSheetitem = $("#luckysheet-sheets-item" + index);
                        luckysheetcurrentSheetitem.hide();

                        $("#luckysheet-sheet-area div.luckysheet-sheets-item").removeClass("luckysheet-sheets-item-active");

                        let indicator = luckysheetcurrentSheetitem.nextAll(":visible");
                        if (luckysheetcurrentSheetitem.nextAll(":visible").length > 0) {
                            indicator = indicator.eq(0).data("index");
                        } else {
                            indicator = luckysheetcurrentSheetitem.prevAll(":visible").eq(0).data("index");
                        }
                        $("#luckysheet-sheets-item" + indicator).addClass("luckysheet-sheets-item-active");

                        sheetmanage.changeSheetExec(indicator);
                    }

                    server.sheetDeleSave.push(Store.luckysheetfile[i]);

                    Store.luckysheetfile.splice(i, 1);

	                break;
	            }
	        }

	        $("#luckysheet-sheets-item" + value.deleIndex).remove();
            $("#luckysheet-datavisual-selection-set-" + value.deleIndex).remove();
            sheetmanage.locationSheet();
	    } else if (type == "shr") { // sheet位置
	        for (let x in value) {
	            Store.luckysheetfile[getSheetIndex(x)].order = value[x];
	        }
	    } else if (type == "shre") { // 删除sheet恢复操作
	        for (let i = 0; i < server.sheetDeleSave.length; i++) {
	            if (server.sheetDeleSave[i].index == value.reIndex) {
	                let datav = server.sheetDeleSave[i];

	                Store.luckysheetfile.push(datav);

	                let colorset = '';
	                if (value.color != null) {
	                    colorset = '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 2px; left: 0px; background-color: ' + datav.color + ';"></div>';
	                }

	                $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": datav.index, "active": "", "name": datav.name, "style": "", "colorset": colorset }));
	                $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + datav.index + '" class="luckysheet-datavisual-selection-set"></div>');
	                break;
	            }
	        }
	    } else if (type == "sh") { // 隐藏sheet
	        let op = item.op, cur = item.cur;

	        if (op == "hide") {
	            file.hide = 1;
	            $("#luckysheet-sheets-item" + index).hide();

	            if (index == Store.currentSheetIndex) {
	                $("#luckysheet-sheets-item" + cur).addClass("luckysheet-sheets-item-active");
	                sheetmanage.changeSheetExec(cur);
	            }
	        } else if (op == "show") {
	            file.hide = 0;
	            $("#luckysheet-sheets-item" + index).show();
	        }
            sheetmanage.locationSheet();
	    } else if (type == "c") { // 图表操作 TODO
	        let op = item.op, cid = item.cid;

	        if (op == "add") { // 插入
	            file.chart.push(value);

	            luckysheet.insertChartTosheet(value.sheetIndex, value.dataSheetIndex, value.option, value.chartType, value.selfOption, value.defaultOption, value.row, value.column, value.chart_selection_color, value.chart_id, value.chart_selection_id, value.chartStyle, value.rangeConfigCheck, value.rangeRowCheck, value.rangeColCheck, value.chartMarkConfig, value.chartTitleConfig, value.winWidth, value.winHeight, value.scrollLeft1, value.scrollTop1, value.chartTheme, value.myWidth, value.myHeight, value.myLeft, value.myTop, value.myindexrank1, true);
	        } else if (op == "xy" || op == "wh" || op == "update") { // 移动 缩放 更新
	            for (let i = 0; i < file.chart.length; i++) {
	                let chartjson = file.chart[i];

	                if (chartjson.chart_id == cid) {
	                    for (let item in chartjson) {
	                        for (let vitem in value) {
	                            if (item == vitem) {
	                                chartjson[item] = value[vitem];
	                            }
	                        }
	                    }

	                    sheetmanage.saveChart(chartjson);

	                    return;
	                }
	            }
	        } else if (op == "del") { // 删除
	            for (let i = 0; i < file.chart.length; i++) {
	                let chartjson = file.chart[i];

	                if (chartjson.chart_id == cid) {
	                    file.chart.splice(i, 1);

	                    $("#" + cid).remove();
	                    sheetmanage.delChart($("#" + cid).attr("chart_id"), $("#" + cid).attr("sheetIndex"));

	                    return;
	                }
	            }
	        }
	    } else if (type == "na") { // 表格名称
	        $("#luckysheet_info_detail_input").val(value).css("width", getByteLen(value) * 10);
	    }
    },
    multipleIndex: 0,
    multipleRangeShow: function (id, name, r, c, value) {
    	let _this = this;
        const fullName = name;

	    let row = Store.visibledatarow[r],
	        row_pre = r - 1 == -1 ? 0 : Store.visibledatarow[r - 1],
	        col = Store.visibledatacolumn[c],
	        col_pre = c - 1 == -1 ? 0 : Store.visibledatacolumn[c - 1];

	    let margeset = menuButton.mergeborer(Store.flowdata, r, c);
	    if (!!margeset) {
	        row = margeset.row[1];
	        row_pre = margeset.row[0];

	        col = margeset.column[1];
	        col_pre = margeset.column[0];
        }

        // 超出16个字符就显示...
        if (getByteLen(name) > 16) {
            name = getByteLen(name, 16) + "...";
        }

        // 如果正在编辑，就显示“正在输入”
        if (value === 'enterEdit') {
            name += " " + locale().edit.typing;
        }

	    if ($("#luckysheet-multipleRange-show-" + id).length > 0) {
            $("#luckysheet-multipleRange-show-" + id).css({ "position": "absolute", "left": col_pre - 1, "width": col - col_pre - 1, "top": row_pre - 1, "height": row - row_pre - 1 });

            $("#luckysheet-multipleRange-show-" + id + " .username").text(name);
            $("#luckysheet-multipleRange-show-" + id + " .username").show();

            if (Store.cooperativeEdit.usernameTimeout['user' + id] != null) {
                clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]);
            }
            Store.cooperativeEdit.usernameTimeout['user' + id] = setTimeout(() => {
                clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]);
                Store.cooperativeEdit.usernameTimeout['user' + id] = null;
            }, 10 * 1000);
	    } else {
	        // let itemHtml = '<div id="luckysheet-multipleRange-show-'+ id +'" data-color="'+ luckyColor[_this.multipleIndex] +'" title="'+ name +'" style="position: absolute;left: '+ (col_pre - 1) +'px;width: '+ (col - col_pre - 1) +'px;top: '+ (row_pre - 1) +'px;height: '+ (row - row_pre - 1) +'px;border: 1px solid '+ luckyColor[_this.multipleIndex] +';z-index: 15;">'+
	        //                 '<div style="width: 100%;height: 100%;position: absolute;top: 0;right: 0;bottom: 0;left: 0;opacity: 0.03;background-color: '+ luckyColor[_this.multipleIndex] +'"></div>'+
            //                '</div>';

            let itemHtml = `<div
								id="luckysheet-multipleRange-show-${id}"
								class="luckysheet-multipleRange-show"
								data-color="${luckyColor[_this.multipleIndex]}"
								title="${fullName}"
								style="position: absolute;left: ${col_pre - 1}px;width: ${col - col_pre - 1}px;top: ${row_pre - 1}px;height: ${row - row_pre - 1}px;border: 1px solid ${luckyColor[_this.multipleIndex]};z-index: 15;">

								<div class="username" style="height: 19px;line-height:19px;width: max-content;position: absolute;bottom: ${row - row_pre - 1}px;right: 0;background-color: ${luckyColor[_this.multipleIndex]};color:#ffffff;padding:0 10px;">
								${name}
								</div>

								<div style="width: 100%;height: 100%;position: absolute;top: 0;right: 0;bottom: 0;left: 0;opacity: 0.03;background-color: ${luckyColor[_this.multipleIndex]}">
								</div>

							</div>`;
            // 正在输入

	        $(itemHtml).appendTo($("#luckysheet-cell-main #luckysheet-multipleRange-show"));

            _this.multipleIndex++;

            // 设定允许用户名消失的定时器，10秒后用户名可隐藏
            // 10秒之类，用户操作界面不会隐藏用户名；10秒之后如果用户操作了界面，则隐藏用户名，没操作就不隐藏
            if (Store.cooperativeEdit.usernameTimeout['user' + id] != null) {
                clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]);
            }
            Store.cooperativeEdit.usernameTimeout['user' + id] = setTimeout(() => {
                clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]);
                Store.cooperativeEdit.usernameTimeout['user' + id] = null;
            }, 10 * 1000);
	    }
    },
    sheetDeleSave: [], // 共享编辑模式下 删除的sheet保存下来，方便恢复时取值
    submitInterval: 1000,
    imagesubmitInterval: 5000,
    submitdatalimit: 50,
    submitcompresslimit: 1000,
    checksubmit: function (data) {
        let _this = this;
        // clearTimeout(_this.requestTimeOut);

        _this.submitTimeout();

        clearTimeout(_this.imageRequestTimeout);
        _this.imageRequestTimeout = setTimeout(function () {
            _this.imageRequest();
        }, _this.imagesubmitInterval);
    },
    submitTimeout: function () {
        let _this = this;
        clearTimeout(_this.requestTimeOut);

        // console.log(_this.requestlast, dayjs(), (_this.requestlast!=null && _this.requestlast.add(10, 'seconds').isBefore(dayjs()) ) );
        if (!_this.requestLock && (_this.requestlast != null && _this.requestlast.clone().add(1, 'seconds').isBefore(dayjs()))) {
            _this.request();
        }

        // if(!_this.imageRequestLock && (_this.imageRequestLast==null || _this.imageRequestLast.clone().add(30, 'seconds').isBefore(dayjs()) ) ){

        // }

        _this.requestTimeOut = setTimeout(function () {
            _this.submitTimeout();
        }, _this.submitInterval);
    },
    requestLock: false,
    requestlast: null,
    firstchange: true,
    requestTimeOut: null,
    request: function () {
        let _this = this;
        let key = this.gridKey;
        let cahce_key = key + "__qkcache";

        _this.cachelocaldata(function (cahce_key, params) {
            if (params.length == 0) {
                return;
            }

            params = encodeURIComponent(JSON.stringify(params));
            let compressBeginLen = params.length;
            let iscommpress = false;
            // if (compressBeginLen > _this.submitcompresslimit) {
            //     params = pako.gzip(params, { to: "string" });
            //     iscommpress = true;
            // }
            _this.requestLock = true;
            // console.log(params);
            // console.log("request");
            if (_this.updateUrl != "") {
                $.post(_this.updateUrl, { compress: iscommpress, gridKey: _this.gridKey, data: params }, function (data) {
                    let re = new Function("return " + data)();
                    if (re.status) {
                        $("#luckysheet_info_detail_update").html("最近存档时间:" + dayjs().format("M-D H:m:s"));
                        $("#luckysheet_info_detail_save").html("同步成功");
                        _this.clearcachelocaldata();
                    } else {
                        $("#luckysheet_info_detail_save").html("<span style='color:#ff2121'>同步失败</span>");
                        _this.restorecachelocaldata();
                    }
                    _this.requestlast = dayjs();
                    _this.requestLock = false;
                });
            }
        });
    },
    imageRequestLast: null,
    imageRequestLock: false,
    imageRequestTimeout: null,
    imageRequest: function () {
        let _this = this;
        // TODO container未定义
        // eslint-disable-next-line no-undef
        html2canvas($("#" + container).find(".luckysheet-grid-window").get(0), {
            onrendered: function (canvas) {
            // let imgcut = $("#luckysheet-cell-main").find(".luckysheet-grid-window");
            // document.body.appendChild(canvas);
                let old = $(canvas).appendTo("body");
                old.hide();
                let newwidth = old.width();
                let newheight = old.height();
                let imageData = old.get(0).getContext("2d").getImageData(0, 0, newwidth, newheight);

                let cutW = newwidth, cutH = newheight;
                if (cutW * 0.54 > cutH) {
                    cutW = cutH / 0.54;
                } else {
                    cutH = cutW * 0.54;
                }
                let newCanvas = $("<canvas>").attr("width", cutW).attr("height", cutH)[0];

                newCanvas.getContext("2d").putImageData(imageData, 0, 0);

                old.attr("width", 350);
                old.attr("height", 189);
                old.get(0).getContext("2d").drawImage(newCanvas, 0, 0, 350, 189);
                let base64 = old.get(0).toDataURL('image/jpeg', 0.9);

                // console.log(base64);
                // console.log("压缩：", pako.gzip(base64, { to: "string" }));
                // console.log("imageRequest");
                let curindex = luckysheet.sheetmanage.getCurSheetnoset();
                _this.imageRequestLock = true;
                // let data1 = pako.gzip(encodeURIComponent(JSON.stringify({"t":"thumb", "img": base64, "curindex":curindex })), { to: "string" });
                let data1 = encodeURIComponent(JSON.stringify({ "t": "thumb", "img": base64, "curindex": curindex }));
                old.remove();
                // console.log("缩略图", _this.imageRequestLast,base64);
                if (_this.updateImageUrl != "") {
                // $.post(_this.updateImageUrl, { compress: true, gridKey: _this.gridKey, data:data1  }, function (data) {
                    $.post(_this.updateImageUrl, { compress: false, gridKey: _this.gridKey, data: data1  }, function (data) {
                        let re = new Function("return " + data)();
                        if (re.status) {
                            _this.imageRequestLast = dayjs();
                        } else {
                            $("#luckysheet_info_detail_save").html("<span style='color:#ff2121'>网络不稳定</span>");
                        }
                        _this.imageRequestLock = true;
                    });
                }
            }
        });
    },
    localdata: [],
    matchOpt: function (v, d) {
        for (let vitem in v) {
            if (vitem == "t" && v.t in { "drc": 1, "arc": 1, "sha": 1, "shc": 1, "shd": 1 }) {
                return false;
            }

            if (vitem == "v") {
                continue;
            }

            if (!(vitem in d)) {
                return false;
            }

            if (d[vitem] != v[vitem]) {
                return false;
            }
        }

        return true;
    },
    deleteRepeatOpt: function (data, value) {
        // let d = $.extend(true, [], data); //原来
        let d = data;
        let _this = this;

        if (value instanceof Array) {
            for (let i = 0; i < value.length; i++) {
                let vitem = value[i];

                for (let a = 0; a < d.length; a++) {
                    let ditem = data[i]; // let ditem = data[a];?

                    if (_this.matchOpt(vitem, ditem)) {
                        delete d[a];
                    }
                }
            }
        } else {
            for (let a = 0; a < d.length; a++) {
                let ditem = d[a];

                if (_this.matchOpt(value, ditem)) {
                    delete d[a];
                }
            }
        }

        let ret = [];
        for (let i = 0; i < d.length; i++) {
            if (d[i] != null) {
                ret.push(d[i]);
            }
        }

        return ret;
    },
    setlocaldata: function (value, func) {
        let key = this.gridKey;
        // store.push(key, data);
        let _this = this;
        _this.getlocaldata(function (data) {
            if (data == null) {
                data = [];
            }

            // 此处不去重，在request同步后台时统一循环一次去重
            // let data = _this.deleteRepeatOpt(data, value);

            if (value instanceof Array) {
                data = data.concat(value);
            } else {
                data.push(value);
            }

            _this.localdata = data;
            func(_this.localdata);

            // console.log(value);
            // localforage.setItem(key, data).then(function () {
            //     console.log(data);
            //     func(data);
            // }).catch(function (err) {

            // });
        });
    },
    getlocaldata: function (func) {
        let key = this.gridKey;
        // return store.get(key);
        func(this.localdata);
        // localforage.getItem(key).then(function(readValue) {
        //     func(readValue);
        // });
    },
    clearlocaldata: function (func) {
        let key = this.gridKey;
        // store.remove(key);
        this.localdata = [];
        func();
        // localforage.removeItem(key, function(err,value) {
        //     func();
        // });
    },
    cachelocaldata: function (func) {
        let key = this.gridKey;
        let _this = this;
        let cahce_key = key + "__qkcache";
        // store.remove(key);
        // console.log(key, cahce_key);

        // 处理localdata去重
        let updatedata = _this.localdata;
        let uLen = updatedata.length;
        if (uLen > 1) {
            let prevData = [];
            prevData[0] = updatedata[0];
            for (let i = 1; i < uLen; i++) {
                let value = updatedata[i];
                let flag = true;
                for (let a = 0; a < prevData.length; a++) {
                    let ditem = prevData[a];
                    if (_this.matchOpt(value, ditem)) {
                        prevData.splice(a, 1, value);
                        flag = false; // 如果已匹配重复，则后续无需再加
                        break;
                    }
                }
                if (flag) {
                    prevData = prevData.concat(value);
                }
            }
            updatedata = prevData;
        }
        if (updatedata == null || updatedata.length == 0) {
            return;
        }
        // console.log(key, cahce_key,updatedata);
        _this.clearlocaldata(function () {
            localforage.setItem(cahce_key, updatedata).then(function () {
                func(cahce_key, updatedata);
            });
        });

        // localforage.getItem(key).then(function(readValue) {
        //     let updatedata = readValue;
        //     if(readValue==null || readValue.length==0){
        //         return;
        //     }
        //     //console.log(key, cahce_key,updatedata);
        //     _this.clearlocaldata(function(){
        //         localforage.setItem(cahce_key, updatedata).then(function () {
        //             func(cahce_key, updatedata);
        //         });
        //     });
        // });
    },
    clearcachelocaldata: function (func) {
        let key = this.gridKey;
        let cahce_key = key + "__qkcache";
        // store.remove(key);
        localforage.removeItem(cahce_key, function (_err, value) {
            if (func && typeof (func) == "function") {
                func();
            }
        });
    },
    restorecachelocaldata: function (func) {
        let key = this.gridKey;
        let cahce_key = key + "__qkcache";
        let _this = this;
        localforage.getItem(cahce_key).then(function (readValue) {
            let updatedata = readValue;
            _this.getlocaldata(function (data) {
                if (data == null) {
                    data = [];
                }
                let newdata = updatedata.concat(data);
                // data.unshift(updatedata);

                _this.localdata = newdata;
                if (func instanceof Function) {
                    func(_this.localdata);
                }

                // localforage.setItem(key, newdata).then(function () {
                //     func(newdata);
                // }).catch(function (err) {

                // });
            });
        });
    },
    keepHighLightBox: function () {
        Store.cooperativeEdit.checkoutData.forEach(value => {
            if (value.index == Store.currentSheetIndex) {
                if (value.op === 'enterEdit') {
                    server.multipleRangeShow(value.id, value.username, value.r, value.c, value.op);
                } else {
                    server.multipleRangeShow(value.id, value.username, value.r, value.c);
                }
            }
        });
    }
};

export default server;
